#  This file is part of codeorge
#  Copyright (C) 2009 Johan Jordaan (www.johanjordaan.co.za)
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.


class FSMState:
  def __init__(self,fsm,accepting=False,enter_function=lambda: True ,exit_function=lambda: True ):
    self.fsm = fsm
    self.accepting = accepting
    self.enter_function = enter_function
    self.exit_function = exit_function
    self.in_transitions = []
    self.out_transitions = []
  
  def accepts(self,input,input_index=0):
    accepted = False
    for transition in self.out_transitions:
      accepted = accepted or transition.accepts(input,input_index)
    if self.accepting:
      self.fsm.accepted_inputs.append(input[:input_index])
    return accepted or self.accepting
        
  def execute(self,input,input_index=0):
    self.enter_function()
    for transition in self.out_transitions:
      transition.execute(input,input_index)
      
  def add_transition(self,name,transition_function,accepting=False,enter_function=lambda:True,exit_function=lambda:True):
    FSMTransition(self,FSMState(self.fsm,accepting,enter_function,exit_function),transition_function,name=name)
  
  
class FSMTransition:
  def __init__(self,source,destination,transition_function,name=None):
    self.source = source
    self.destination = destination
    self.transition_function = transition_function
    self.destination.in_transitions.append(self)
    self.source.out_transitions.append(self)
    self.name = name
    
  def accepts(self,input,input_index=0):
    if input_index < len(input) and self.transition_function(input,input_index):
      return self.destination.accepts(input,input_index+1)
    else:
      return False
  
  def execute(self,input,input_index=0):
    if input_index < len(input) and self.transition_function(input,input_index):
      self.destination.execute(input,input_index+1)
      self.source.exit_function()
      
  def __eq__(self,s):
    return self.name == s.name
    
  
class FSM:
  def __init__(self,accepting=False,enter_function=lambda: True ,exit_function=lambda: True):
    self.start_state = FSMState(self,accepting,enter_function,exit_function)
    self.accepted_inputs = []

  def accepts(self,input,input_index=0):
    self.accepted_inputs = []
    return self.start_state.accepts(input,input_index) 
    
  def execute(self,input,input_index=0):
    self.start_state.execute(input,input_index)
    
 
